#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
	QMainWindow(parent), _worldTransformation(), pointSize(64)
{
	setupUi(this);
	myView->setScene(&_scene);

	pointFound = NULL;
	_currentCurve = NULL;
	creating_curve = false;

	connect(myView, SIGNAL(zoomChanged(int)), this, SLOT(adjustSlider(int)));
	connect(myView, SIGNAL(mouseDoubleClickDrag(QPointF)), this, SLOT(mouseDragDoubleClick(QPointF)));
	connect(myView, SIGNAL(mouseMoveDrag(QPointF)), this, SLOT(mouseDragMove(QPointF)));
	connect(myView, SIGNAL(mouseReleaseDrag()), this, SLOT(mouseDragRelease()));
	connect(myView, SIGNAL(createPoint(QPointF)), this, SLOT(createPoint(QPointF)));

	adjustTransform();
	drawAxis();
}

void MainWindow::adjustSlider(int d)
{
	zoomSlider->setValue(zoomSlider->value()+d);
}

void MainWindow::adjustTransform()
{
	pointSize = (zoomSlider->value()/100.0)*64;

	_worldTransformation.reset();

	_worldTransformation.translate(MAX_SIZE*pointSize, MAX_SIZE*pointSize);
	_worldTransformation.scale(pointSize,-pointSize);

	myView->setTransform(_worldTransformation);
	plotCurves();
}

void MainWindow::changeColor()
{
	if( !_currentCurve ) return;

	QColor c = QColorDialog::getColor(_currentCurve->getColor(), this);

	_currentCurve->setColor(c);

	loadCurveOptions();
	plotCurves();
}

void MainWindow::reset()
{
	for (int i = 0; i < _curves.size(); ++i)
	{
		_curves[i]->clear (_scene);
		delete _curves[i];
	}
	_curves.clear();

	_currentCurve = NULL;
	emit enableStepsSlider (false);

	loadCurveOptions();
	plotCurves();
}

void MainWindow::load()
{
	QString filename = QFileDialog::getOpenFileName(this, tr("Choose a file"),
														 QDir::currentPath(), "*.xml");

	// Open Main Filestream
	if( filename.isEmpty() )
		return;

	reset();

	QDomDocument doc;
	QFile file(filename);

	if( !file.open(QIODevice::ReadOnly) )
		return;

	QString error;
	if (!doc.setContent(&file, &error)) {
		qDebug() << "Failed to set DOC content : " << error;
		file.close();
		return;
	}
	file.close();

	// LOOAD!

	QDomElement root = doc.documentElement();

	int n = 1;

	QDomElement e = root.firstChildElement();

	while(!e.isNull())
	{
		if( e.tagName() == "curva" )
		{
			QString format = e.attribute("formato", "");
			QString steps_str = e.attribute ("resolucao", "");

			if( QString::compare (format, "bezier", Qt::CaseInsensitive) == 0 )
			{
				Curva *c = new CurvaBezier;

				c->read(e);

				if (!steps_str.isEmpty() && !steps_str.isNull())
					c->max_steps() = qMax<int> (1, qMin<int> (100, steps_str.toInt()));

				if( !c->validate() )
				{
					qDebug() << "\t" << "Invalid Bezier Curve setup on curve number " << n;
				}

				_curves.push_back(c);
				//_currentCurve = c;
			}
			else if( QString::compare (format, "hermit", Qt::CaseInsensitive) == 0 )
			{
				Curva *c = new CurvaHermit;

				c->read(e);

				if (!steps_str.isEmpty() && !steps_str.isNull())
					c->max_steps() = qMax<int> (1, qMin<int> (100, steps_str.toInt()));

				if( !c->validate() )
				{
					qDebug() << "\t" << "Invalid Hermit Curve setup on curve number " << n;
				}

				_curves.push_back(c);
			}
			else
			{
				qDebug() << "Unknow Curve Format : " << format;
			}
		}
		else
		{
			qDebug() << "Unkown Tag Name : " << e.tagName();
		}

		e = e.nextSiblingElement();
		n++;
	}

	loadCurveOptions();

	qDebug() << "Loading Finished!";
	adjustTransform();
}

void MainWindow::save()
{
	QString filename = QFileDialog::getSaveFileName(this, tr("Choose a file"),
														 QDir::currentPath(), "*.xml");

	// Open Main Filestream
	if( filename.isEmpty() )
		return;

	QDomDocument doc;
	QFile file(filename);
	if( !file.open(QIODevice::WriteOnly) )
		return;

	QDomNode root = doc.createElement("Trabalho2");

	doc.appendChild(root);

	QTextStream text(&file);


	for( int i = 0; i < _curves.size(); ++i )
	{
		root.appendChild(_curves[i]->save(doc));
	}


	doc.save(text, 4);
	file.close();
}

void MainWindow::loadCurveOptions()
{
	if( _currentCurve )
	{
		colorButton->setEnabled(true);
		saveImageButton->setEnabled(true);
		deleteCurve->setEnabled(true);
		QPixmap p(1,1);

		p.fill(_currentCurve->getColor());

		curveColor->setPixmap(p);
	}
	else
	{
		colorButton->setEnabled(false);
		saveImageButton->setEnabled(false);
		deleteCurve->setEnabled(false);
		curveColor->clear();
	}
}

void MainWindow::saveCurrentCurveAsImage()
{
	if( _currentCurve )
	{
		QString filename = QFileDialog::getSaveFileName(this, tr("Choose a file"),
															 QDir::currentPath(), "*.png");


		QImage im = _currentCurve->draw();


		im.save(filename);
	}
}

void MainWindow::drawAxis()
{
	QPen axisPen;

	axisPen.setWidthF(1/pointSize);

	_scene.addLine(-MAX_SIZE, 0, MAX_SIZE, 0, axisPen);
	for( int i = 1; i <= MAX_SIZE; ++i )
	{
		// X AXIS
		_scene.addLine(i, (i%5)?0.5:2, i, (i%5)?-0.5:-2, axisPen);
		_scene.addLine(-i, (i%5)?0.5:2, -i, (i%5)?-0.5:-2, axisPen);
	}

	_scene.addLine(0, -MAX_SIZE, 0, MAX_SIZE, axisPen);
	for( int i = 1; i <= MAX_SIZE; ++i )
	{
		// Y AXIS
		_scene.addLine((i%5)?0.5:2, i,(i%5)?-0.5:-2, i, axisPen);
		_scene.addLine((i%5)?0.5:2, -i,(i%5)?-0.5:-2, -i, axisPen);
	}
}

void MainWindow::plotCurves()
{
	for( int i = 0; i < _curves.size(); ++i )
	{
		_curves[i]->clear (_scene);
	}

	QPen p;

	p.setWidthF(1/(pointSize/4));
	p.setCapStyle(Qt::RoundCap);

	if( _currentCurve ) _currentCurve->plot(_scene, p, FechoConvexo);

	if( controlPointsCheckbox->isChecked() )
	{
		for( int i = 0; i < _curves.size(); ++i )
		{
			_curves[i]->plot(_scene, p, ControlMode);
		}
	}

	p.setWidthF(1.0 / pointSize);
	p.setCapStyle(Qt::RoundCap);

	for( int i = 0; i < _curves.size(); ++i )
	{
		_curves[i]->plot(_scene, p, CurveMode);
	}
}

void MainWindow::mouseDragDoubleClick (QPointF p)
{
	p = myView->viewportTransform().inverted().map (p);
	pointFound = NULL;

	for (int i = 0; i < _curves.size(); ++i)
	{
		pointFound = _curves[i]->selectPoint (p, 32.0 / (pointSize * pointSize));

		if (pointFound)
		{
			_currentCurve = _curves[i];
			emit enableStepsSlider (true);
			emit setStepsSlider (_currentCurve->max_steps());

			loadCurveOptions();
			plotCurves();
			return;
		}
	}

	_currentCurve = NULL;
	emit enableStepsSlider (false);
	loadCurveOptions();
	plotCurves();
}

void MainWindow::mouseDragMove (QPointF p)
{
	if (pointFound != NULL)
	{
		p = myView->viewportTransform().inverted().map (p);

		pointFound->setX (p.x());
		pointFound->setY (p.y());

		plotCurves();
	}
}

void MainWindow::mouseDragRelease (void)
{
	//plotCurves();
}

void MainWindow::createPoint (QPointF p)
{
	if (creating_curve && _currentCurve != _curves[_curves.size() - 1])
	{
		_curves.remove (_curves.size() - 1);
	}

	p = myView->viewportTransform().inverted().map (p);

	if (_currentCurve)
	{
		_currentCurve->addPoint (p);
		plotCurves();
	}

	creating_curve = false;
}

void MainWindow::createBezierCurve (void)
{
	if (creating_curve) return;
	creating_curve = true;

	_currentCurve = new CurvaBezier;
	_curves.append (_currentCurve);

	emit enableStepsSlider (true);
	emit setStepsSlider (_currentCurve->max_steps());

	loadCurveOptions();
}

void MainWindow::createHermitCurve (void)
{
	if (creating_curve) return;
	creating_curve = true;

	_currentCurve = new CurvaHermit;
	_curves.append (_currentCurve);

	emit enableStepsSlider (true);
	emit setStepsSlider (_currentCurve->max_steps());

	loadCurveOptions();
}

void MainWindow::deletePoint (void)
{
	if (pointFound == NULL) return;

	for (int i = 0; i < _curves.size(); ++i)
	{
		if (_curves[i]->removePoint (pointFound))
		{
			if(!_curves[i]->minimumValidate())
			{
				_curves[i]->clear (_scene);
				delete _curves[i];
				_curves.remove (i);
				_currentCurve = NULL;
				pointFound = NULL;
				emit enableStepsSlider (false);
			}

			loadCurveOptions();
			plotCurves();
			return;
		}
	}
}

void MainWindow::deleteCurrentCurve (void)
{
	if (_currentCurve == NULL) return;

	int i = _curves.indexOf(_currentCurve);

	_currentCurve->clear (_scene);
	_curves.remove (i);
	delete _currentCurve;

	_currentCurve = NULL;
	emit enableStepsSlider (false);

	loadCurveOptions();
	plotCurves();
}

void MainWindow::stepsSliderChanged (int steps)
{
	if (_currentCurve == NULL) return;

	_currentCurve->max_steps() = steps;

	plotCurves();
}
